package com.cy.pj.sys.server.aspect;

import com.cy.pj.common.annotation.RequiredLog;
import com.cy.pj.sys.pojo.SysLog;
import com.cy.pj.sys.server.SysLogService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Date;

/**
 * @DATE: 2021/3/16 19:53
 * @Author: LuckyH
 */

// 创建切面对象，用于做日志业务增强
@Aspect
@Component
public class SysLogAspect {
    private static final Logger log =
            LoggerFactory.getLogger(SysLogAspect.class);

    @Autowired
    private SysLogService sysLogService;

    /**
     * @pointcut 注解定义切入点
     * @annotation 切入点表达式，后续由此注解描述的方法为切入点方法
     */
    @Pointcut("@annotation(com.cy.pj.common.annotation.RequiredLog)")
    public void doLog(){

    }

    /**
     * @around 描述的方法，可以在切入点执行之前和执行之后进行业务拓展
     * @param jp 连接点对象，此对象封装了要执行的目标方法信息
     *           可以通过连接点对象调用目标方法
     * @return  目标方法的执行结果
     * @throws Throwable
     */
    @Around("doLog()")
    public Object doAround(ProceedingJoinPoint jp) throws Throwable {
        long t1 = System.currentTimeMillis();
        log.info("Start:{}",t1);
        try{
            Object result = jp.proceed();
            long t2 = System.currentTimeMillis();
            log.info("After:{}",t2);
            doLogInfo(jp,t2-t1,null);
            //log.info("opertime:{}",t2-t1);

            // 返回data 对于不需要分页的业务
            return result;
        }catch (Throwable e){
            e.printStackTrace();
            long t3 = System.currentTimeMillis();
            //log.info("exception:{}",e.getMessage());
            doLogInfo(jp, t3-t1, e);
            throw e;
        }

    }

    private void doLogInfo(ProceedingJoinPoint jp, long time, Throwable e) throws Exception {

        //获取用户行为日志
        String username = "cgb";
        // 获取用户登录的IP地址
        String ip="202.106.20";
        // 获取字节码对象
        Class<?> targetCls = jp.getTarget().getClass();
        // 获取签名
        MethodSignature ms = (MethodSignature)jp.getSignature();
        // 获取方法
        Method targetMethod = targetCls.getMethod(ms.getName(), ms.getParameterTypes());
        System.out.println(targetMethod);

        // 拿到方法上面的注解
        RequiredLog annotation = targetMethod.getAnnotation(RequiredLog.class);
        // 拿到注解东西（参数）
        String operation = annotation.operation();
        // 包名+类名  方法名
        String classMethodName = targetCls.getName() + "." + targetMethod.getName();
//        System.out.println(targetCls.getName());
//        System.out.println(targetMethod.getName());
//
        Object[] args = jp.getArgs();
//        for (Object arg : args) {
//            System.out.println(arg);
//        }
        String params = new ObjectMapper().writeValueAsString(args);
        //System.out.println(params);

        SysLog sysLog = new SysLog();
        sysLog.setStatus(1);
        sysLog.setCreatedTime(new Date());
        sysLog.setUsername(username);
        sysLog.setIp(ip);
        sysLog.setOperation(operation);
        sysLog.setMethod(classMethodName);
        sysLog.setParams(params);
        sysLog.setTime(time);

        if (e!=null){
            sysLog.setStatus(0);
            sysLog.setError(e.getMessage());
        }

        String userLog = new ObjectMapper().writeValueAsString(sysLog);

        sysLogService.insertLog(sysLog);
        log.info("user,oper{}",userLog);


//        new Thread(){
//            @Override
//            public void run() {
//                sysLogService.insertLog(sysLog);
//            }
//        }.start();

    }

}
